﻿using System;
using System.IO;

namespace CS.Beehive
{
    /// <summary>
    /// 接收Buffer
    /// </summary>
    internal class ReceiveBuffer
    {
        /// <summary>
        /// Buffer内容
        /// </summary>
        private byte[] _buffer;
        /// <summary>
        /// Buffer默认大小(可变)
        /// </summary>
        private readonly int _bufferSize = 8192;
        /// <summary>
        /// 锁
        /// </summary>
        private readonly object _syncRoot = new object();
        /// <summary>
        /// 偏移位置
        /// </summary>
        internal int Offset;
        /// <summary>
        /// 当前有效数据总长度（可能不止一个有效数据段）
        /// </summary>
        internal int Length;
        /// <summary>
        /// 当前包长度(可通过该参数进行是否丢包断线的相关逻辑决策)
        /// </summary>
        internal int Size;
        /// <summary>
        /// 用缓冲大小初始化Buffer
        /// </summary>
        /// <param name="bufferSize">介于8K之1M之间</param>
        public ReceiveBuffer(int bufferSize)
        {
            _bufferSize =bufferSize.ToInt(8192,1048576);
            _buffer = new byte[_bufferSize];
            Offset = 0;
            Length = 0;
        }

        /// <summary>
        /// 将参数buffer附加至原已存在的后
        /// <remarks>TODO:存时不可更改Offset位置，否则没读出来的话就会丢失数据，下面算法有待测试与改进。</remarks>
        /// </summary>
        /// <param name="buffer">来源缓存</param>
        /// <param name="offset">来源偏移量</param>
        /// <param name="length">来源长度</param>
        public void Set(byte[] buffer, int offset, int length)
        {
            lock (_syncRoot)
            {
                var newLength = Length + length; //新数据总长
                if (_buffer.Length - Offset >= newLength)
                {
                    //可直接填充
                    //Tracer.Trace("偏移填充");
                    Array.Copy(buffer, offset, _buffer, Offset + Length, length);
                    Length += length;
                }
                else if ((_buffer.Length - Offset < newLength) && (_buffer.Length >= newLength))
                {
                    //重置
                    //Tracer.Trace("Buffer重置");
                    Array.Copy(_buffer, Offset, _buffer, 0, Length); //重置
                    Array.Copy(buffer, offset, _buffer, Length, length);
                    Offset = 0;
                    Length += length;
                }
                else // if( _buffer.Length < newLength)
                {
                    //扩容并重置
                    //Tracer.Trace("扩容一次");
                    var tmpBuffer = new byte[Length + length];
                    Array.Copy(_buffer, 0, tmpBuffer, 0, Length);
                    Array.Copy(buffer, offset, tmpBuffer, Length, length);
                    _buffer = tmpBuffer;
                    Offset = 0;
                    Length = _buffer.Length;
                }
            }
        }

        /// <summary>
        /// 获取所有内容
        /// </summary>
        /// <returns></returns>
        public byte[] GetAll()
        {
            byte[] result;
            lock (_syncRoot)
            {
                result = new byte[Length];
                Array.Copy(_buffer, Offset, result, 0, Length);
                Offset = 0;
                Length = 0;
            }
            return result;
        }

        /// <summary>
        /// 取得一个包文(可能取不到)
        /// </summary>
        /// <returns></returns>
        public byte[] GetDatagaram()
        {
            byte[] result = null;
            lock (_syncRoot)
            {
                Size = PeekInt();
                if (Size > 0 && Size <= Length)
                {
                    result = new byte[Size];
                    Array.Copy(_buffer, Offset, result, 0, Size);
                    Offset += Size;
                    Length -= Size;
                }
                //TCP传输出现破包（断包），因此这儿抛出异常中断其连接，由客户端重连处理。
                else if (Size > Length)
                {
                    throw new InvalidDataException("缓存区数据不足以提供必要信息(出现破包)");
                }
            }
            return result;
        }

        /// <summary>
        /// 取得数据长度
        /// </summary>
        /// <returns>
        /// 0  表示没有足够的长度
        /// -1 内部异常，该Buffer要被丢弃
        /// </returns>
        internal int PeekInt()
        {
            var result = 0;
            lock (_syncRoot)
            {
                if (Length >= 4)
                {
                    result = BitConverter.ToInt32(_buffer, Offset);
                }
            }
            return result;
        }

    }
}